import pygame
import sys
import math
import random

# ================== 配置参数 ==================
width, height = 800, 600
block_size = 20
speed = 3
margin = 2  # 碰撞误差容忍度

# ================== 初始化 ==================
def init_game():
    pygame.init()
    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption("Pygame 按角度发射方块")
    return screen

# ================== 工具函数 ==================
def random_color():
    """生成一个非黑色的随机颜色"""
    while True:
        color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        if color != (0, 0, 0):
            return color

def create_block(mouse_pos, start_point, block_size, speed):
    """创建一个新的方块对象"""
    dx = mouse_pos[0] - start_point[0]
    dy = mouse_pos[1] - start_point[1]

    if dx == 0 and dy == 0:
        return None

    norm = math.hypot(dx, dy)
    dir_x = dx / norm
    dir_y = dy / norm

    vx = dir_x * speed
    vy = dir_y * speed

    return {
        'x': 0,
        'y': height - block_size,
        'vx': vx,
        'vy': vy,
        'color': random_color(),
        'state': 'flying',
        'only_fall': False
    }

# ================== 事件处理 ==================
def handle_events(blocks, block_size, speed):
    """处理鼠标点击等事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            return False

        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pos = pygame.mouse.get_pos()
            start_point = (0, height)

            new_block = create_block(mouse_pos, start_point, block_size, speed)
            if new_block:
                blocks.append(new_block)

    return True

# ================== 更新逻辑 ==================
def update_blocks(blocks, width, height, block_size, margin):
    """更新所有方块的状态和位置"""
    for block in blocks:
        if block.get('state') == 'stopped':
            continue

        only_fall = block.get('only_fall', False)

        # 垂直方向持续更新
        block['y'] += block['vy']

        # 横向移动控制
        if not only_fall:
            block['x'] += block['vx']
        else:
            block['vx'] = 0

        current_rect = pygame.Rect(int(block['x']), int(block['y']), block_size, block_size)

        # 仅下落模式：检查是否可以继续下落
        if only_fall:
            below_y = block['y'] + block_size + margin
            below_rect = pygame.Rect(int(block['x']), int(below_y), block_size, 1)

            below_solid = False
            for other in blocks:
                if other is block or other.get('state') != 'stopped':
                    continue
                other_rect = pygame.Rect(int(other['x']), int(other['y']), block_size, block_size)
                if below_rect.colliderect(other_rect):
                    below_solid = True
                    break

            if below_solid or block['y'] + block_size >= height:
                if below_solid:
                    block['y'] = other['y'] - block_size
                else:
                    block['y'] = height - block_size
                block['vy'] = 0
                block['state'] = 'stopped'

        else:
            # 正常飞行状态下检测是否碰到已落地方块
            collided = False
            for other in blocks:
                if other is block or other.get('state') != 'stopped':
                    continue
                other_rect = pygame.Rect(int(other['x']), int(other['y']), block_size, block_size)
                expanded_rect = current_rect.inflate(margin * 2, margin * 2)
                if expanded_rect.colliderect(other_rect):
                    block['vx'] = 0
                    block['vy'] = abs(block['vy'])
                    block['only_fall'] = True
                    collided = True
                    break

            if not collided:
                # 边界反弹逻辑
                if block['y'] <= 0:
                    block['vy'] = abs(block['vy'])
                if block['x'] <= 0:
                    block['vx'] = abs(block['vx'])
                if block['x'] + block_size >= width:
                    block['vx'] = -abs(block['vx'])

        # 最终触底处理
        if block['y'] + block_size >= height:
            block['y'] = height - block_size
            block['vy'] = 0
            block['state'] = 'stopped'

    # 清理静止方块（防止内存泄漏）
    # return [b for b in blocks if b.get('state') != 'stopped']
    return blocks

# ================== 绘图逻辑 ==================
def draw_blocks(screen, blocks, block_size):
    """绘制所有方块"""
    screen.fill((255, 255, 255))  # 白色背景

    for block in blocks:
        rect = pygame.Rect(int(block['x']), int(block['y']), block_size, block_size)

        if block.get('state') == 'stopped':
            # 颜色变灰（降低亮度）
            gray_color = tuple(c // 2 for c in block['color'])
            pygame.draw.rect(screen, gray_color, rect)
        else:
            pygame.draw.rect(screen, block['color'], rect)

# ================== 主程序 ==================
def main():
    screen = init_game()
    clock = pygame.time.Clock()
    blocks = []

    running = True
    while running:
        clock.tick(60)

        # 处理事件
        running = handle_events(blocks, block_size, speed)

        # 更新方块状态
        blocks = update_blocks(blocks, width, height, block_size, margin)

        # 绘图
        draw_blocks(screen, blocks, block_size)

        # 刷新显示
        pygame.display.flip()

    pygame.quit()
    sys.exit()

if __name__ == '__main__':
    main()
